<template>
  <div class="login-box">
    <div class="login-left">
      <el-image :src="login_bg" fit="cover"></el-image>
    </div>
    <div class="login-right">
      <div class="login-logo">
        <div class="login-logo-img"><el-image :src="login_logo"></el-image></div>
        <div class="login-logo-title"><el-image :src="login_title"></el-image></div>
      </div>
      <div class="form">
        <div class="tab">
          <div class="tab-login" @click="accountLogin" :class="tabActive === 'account' ? 'is-active' : ''">账号登录
          </div>
          <div class="tab-login" @click="codeLogin" :class="tabActive === 'code' ? 'is-active' : ''">二维码登录</div>
        </div>
        <el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form" v-if="tabActive === 'account'">
          <el-form-item prop="username">
            <el-input v-model="loginForm.username" type="text" size="large" auto-complete="off" placeholder="账号">
              <template #prefix>
                <svg-icon icon-class="user" class="el-input__icon input-icon" />
              </template>
            </el-input>
          </el-form-item>
          <el-form-item prop="password">
            <el-input v-model="loginForm.password" type="password" size="large" auto-complete="off" placeholder="密码"
              @keyup.enter.native="handleLogin">
              <template #prefix>
                <svg-icon icon-class="password" class="el-input__icon input-icon" />
              </template>
            </el-input>
          </el-form-item>
          <el-form-item prop="code" v-if="captchaEnabled">
            <el-input v-model="loginForm.code" size="large" auto-complete="off" placeholder="验证码" style="width: 63%"
              @keyup.enter.native="handleLogin">
              <template #prefix>
                <svg-icon icon-class="validCode" class="el-input__icon input-icon" />
              </template>
            </el-input>
            <div class="login-code">
              <img :src="codeUrl" @click="getCode" class="login-code-img" />
            </div>
          </el-form-item>
          <el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox>
          <!-- <el-form-item style="float: right">
            <el-button circle title="微信登录" @click="doSocialLogin('wechat')">
              <svg-icon icon-class="wechat" />
            </el-button>
          </el-form-item> -->
          <el-form-item style="width:100%;">
            <el-button :loading="loading" size="large" type="primary" style="width:100%;"
              @click.native.prevent="handleLogin">
              <span v-if="!loading">登 录</span>
              <span v-else>登 录 中...</span>
            </el-button>
            <!-- <div style="float: right;" v-if="register">
              <router-link class="link-type" :to="'/register'">立即注册</router-link>
            </div> -->
          </el-form-item>
        </el-form>
        <div v-if="tabActive === 'code'" class="code-box">
          <div class="code-img" v-loading="loadingCode">
            <el-image :src="codeImageUrl" v-if="codeImageUrl"></el-image>
            <div v-else>{{ codeImageUrl }}</div>
          </div>
          <div class="code-remain">请使用微信扫描二维码</div>
        </div>
      </div>
    </div>
    <!--  底部  -->
    <div class="el-login-footer">
      <span>蜀ICP备2024086687号-2</span>
    </div>
  </div>
</template>

<script setup>
import axios from '../utils/request';
import Fingerprint2 from 'fingerprintjs2'  //浏览器指纹fingerprinting
import { getCodeImg, getTenantList, loginUseCodeAPI, getCodeApi, getUUIDApi } from "@/api/login";
import { authBinding } from '@/api/system/social/auth';
import { setToken } from "@/utils/auth";
import usePermissionStore from '@/store/modules/permission'
import useUserStore from '@/store/modules/user'
import login_bg from '../assets/images/baseImage/img_login.png'
import login_logo from '../assets/images/baseImage/img_logo.png'
// import login_logo from '../assets/logo/logo_copy.png'

import login_title from '../assets/images/baseImage/img_logo_text.png'
const tabActive = ref('account')
const userStore = useUserStore();
const router = useRouter();
const codeImageUrl = ref('')
const loadingCode = ref(true)
let access = ref('')
let client = ref('')
const { proxy } = getCurrentInstance();
let lastLoginTimestamp = ref(0); //记录上次登录的时间戳
const loginForm = ref({
  tenantId: "1",
  // username: "superadmin",
  // password: "*2D#3xcs0mx/",
  username: "",
  password: "",
  rememberMe: false,
  code: "",
  uuid: ""
});

const loginRules = {
  tenantId: [{ required: true, trigger: "blur", message: "请输入您的租户编号" }],
  username: [{ required: true, trigger: "blur", message: "请输入您的账号" }],
  password: [{ required: true, trigger: "blur", message: "请输入您的密码" }],
  code: [{ required: true, trigger: "change", message: "请输入验证码" }]
};
const codeUrl = ref("");
const loading = ref(false);
// 验证码开关
const captchaEnabled = ref(true);
// 注册开关
const register = ref(false);
const redirect = ref(undefined);
const loginRef = ref();
// 租户列表
const tenantList = ref([]);
watch(() => router.currentRoute.value, (newRoute) => {
  redirect.value = newRoute.query && newRoute.query.redirect;
}, { immediate: true });
// 获取浏览器的指纹
const createFingerprint = () => {
  return new Promise((resolve, reject) => {
    if (window.requestIdleCallback) {
      requestIdleCallback(() => {
        Fingerprint2.get((components) => {
          const values = components.map(component => component.value);
          const murmur = Fingerprint2.x64hash128(values.join(""), 31).toUpperCase();
          resolve(murmur);
        });
      });
    } else {
      setTimeout(() => {
        Fingerprint2.get((components) => {
          const values = components.map(component => component.value);
          const murmur = Fingerprint2.x64hash128(values.join(""), 31).toUpperCase();
          resolve(murmur);
        });
      }, 500);
    }
  });
}
const getMurmur = async () => {
  try {
    const murmur = await createFingerprint();
    return murmur;
  } catch (error) {
    throw error;
  }
}
let socketUrl = ""; // socket地址
let websocket = null; // websocket 实例
let heartTime = null; // 心跳定时器实例
let socketHeart = 0; // 心跳次数
const HeartTimeOut = 10000; // 心跳超时时间 10000 = 10s
let socketError = 0; // 错误次数
// 初始化socket
const initWebSocket = (url, token, clientId) => {
  if (!token || !clientId) {
    return;
  }
  socketUrl = url;
  // 初始化 websocket
  websocket = new WebSocket(
    url + "?Authorization=Bearer " + token + "&clientid=" + clientId
  );
  websocketonopen();
  websocketonmessage(token);
  websocketonerror();
  websocketclose();
  sendSocketHeart();
  return websocket;
};

// socket 连接成功
const websocketonopen = () => {
  websocket.onopen = function () {
    // console.log("连接 websocket 成功");
    resetHeart();
  };
};

// socket 连接失败
const websocketonerror = () => {
  websocket.onerror = function (e) {
    // console.log("连接 websocket 失败", e);
  };
};

// socket 断开链接
const websocketclose = () => {
  websocket.onclose = function (e) {
    // console.log("断开连接", e);
  };
};

// socket 重置心跳
const resetHeart = () => {
  socketHeart = 0;
  socketError = 0;
  clearInterval(heartTime);
  sendSocketHeart();
};

// socket心跳发送
const sendSocketHeart = () => {
  heartTime = setInterval(() => {
    // 如果连接正常则发送心跳
    if (websocket.readyState === 1) {
      socketHeart = socketHeart + 1;
    } else {
      // 重连
      reconnect();
    }
  }, HeartTimeOut);
};

// socket重连
const reconnect = () => {
  const token = sessionStorage.getItem('access_token')
  const clientId = sessionStorage.getItem('client_id')
  if (socketError <= 2) {
    clearInterval(heartTime);
    initWebSocket(socketUrl, token, clientId);
    socketError = socketError + 1;
    // eslint-disable-next-line prettier/prettier
    // console.log("socket重连", socketError);
  } else {
    // eslint-disable-next-line prettier/prettier
    // console.log("重试次数已用完");
    clearInterval(heartTime);
  }
};
// socket 接收数据
const websocketonmessage = (token) => {
  // 获取二维码
  getCodeApi(token).then((res) => {
    let u8a = new Uint8Array(res).reduce(
      (res, byte) => res + String.fromCharCode(byte),
      ""
    );
    codeImageUrl.value = `data:image/png;base64,${btoa(u8a)}`;
    loadingCode.value = false
  })
  websocket.onmessage = function (e) {
    try {
      const data = JSON.parse(e.data);
      // 扫码成功
      if (data.msg === "扫码成功") {
        if (data.code === 200) {
          websocket.send(
            JSON.stringify({
              type: "Login",
              scene: data.scene,
            })
          );
        } else if (data.code == 500) {
          //重新建立连接，账号过期
          websocketclose()
          sessionStorage.removeItem('access_token')
          sessionStorage.removeItem('client_id')
          codeLogin()
        } else if (data.code === 501) {
          reconnect(); // 参数错误，用户需要重新扫码
          proxy.$modal.msgError("请重新扫码");
        }
      }
    } catch (error) { }
    try {
      const data = JSON.parse(e.data);
      // 缓存成功拿到token和clientId
      if (data.msg === "缓存成功") {
        if (data.code === "201") {
          getUUIDApi(data.data, token).then(async (res) => {
            // 扫码成功登录
            setToken(res.data.access_token);
            const newClientId = res.data.client_id;
            // 更新 Axios 请求头
            sessionStorage.setItem('clientid', newClientId);
            axios.defaults.headers["clientid"] = newClientId;
            await new Promise((resolve) => setTimeout(resolve, 0));
            await userStore.getInfo()
            await usePermissionStore().generateRoutes()
            proxy.$modal.msgSuccess("扫码成功");
            sessionStorage.removeItem('access_token')
            sessionStorage.removeItem('client_id')
            lastLoginTimestamp.value = 0
            router.push('/')
            window.location.reload()
          })
        } else if (data.code == 500) {
          websocketclose()
          sessionStorage.removeItem('access_token')
          sessionStorage.removeItem('client_id')
          codeLogin()
        } else if (data.code === 501) {
          reconnect(); // 参数错误，用户需要重新扫码
          proxy.$modal.msgError("请重新扫码");
        }
      } else {
        return
      }
    } catch (error) { }
  }
};
// 点击二维码按钮
// 二维码登录获取token和clientId
const getTokenClient = async () => {
  try {
    const fingerprint = await getMurmur();
    const data = {
      tenantId: 1,
      clientId: 'd2f00587cba1cf116b0770361be323de',
      grantType: 'scanCode',
      fingerprinting: fingerprint
    };
    const res = await loginUseCodeAPI(data);
    access.value = res.data.access_token;
    client.value = res.data.client_id;
    sessionStorage.setItem('access_token', res.data.access_token);
    sessionStorage.setItem('client_id', res.data.client_id);
    let protocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://';
    const url = protocol + window.location.host + import.meta.env.VITE_APP_BASE_API + "/resource/websocket";
    // websocket = new WebSocket(url + '?Authorization=Bearer ' + getToken() + '&clientid=' + import.meta.env.VITE_APP_CLIENT_ID);
    initWebSocket(url, access.value, client.value)
  } catch (error) {
    loadingCode.value = false; // 处理错误情况，确保 loadingCode 正确设置
  }
}
const accountLogin = () => {
  tabActive.value = 'account'
}
const codeLogin = () => {
  tabActive.value = 'code'
  loadingCode.value = true
  const currentTimestamp = Date.now();
  const token = sessionStorage.getItem('access_token')
  const clientId = sessionStorage.getItem('client_id')
  if (token === '' || clientId === '') {
    getTokenClient()  // 调取登录和链接websocket
  } else {
    const timeDifference = currentTimestamp - lastLoginTimestamp.value;
    const thirtyMinutesInMillis = 30 * 60 * 1000;
    // 距离上次登录不足30分钟，则不执行登录操作
    if (timeDifference < thirtyMinutesInMillis) {
      reconnect()
      loadingCode.value = false
    } else {
      // 超过30分钟清除缓存
      sessionStorage.removeItem('access_token')
      sessionStorage.removeItem('client_id')
      getTokenClient()
      lastLoginTimestamp.value = currentTimestamp;
    }
  }
}
/**
 * 获取验证码
 */
async function getCode() {
  const res = await getCodeImg();
  const { data } = res;
  captchaEnabled.value = data.captchaEnabled === undefined ? true : data.captchaEnabled;
  if (captchaEnabled.value) {
    codeUrl.value = 'data:image/gif;base64,' + data.img;
    loginForm.value.uuid = data.uuid;
  }
}

function getLoginData() {
  const tenantId = localStorage.getItem("tenantId");
  const username = localStorage.getItem('username');
  const password = localStorage.getItem('password');
  const rememberMe = localStorage.getItem('rememberMe');
  loginForm.value = {
    tenantId: tenantId === null ? loginForm.value.tenantId : tenantId,
    username: username === null ? loginForm.value.username : username,
    password: password === null ? loginForm.value.password : password,
    rememberMe: rememberMe === null ? false : rememberMe
  };
}

function handleLogin() {
  proxy.$refs.loginRef.validate(valid => {
    if (valid) {
      loading.value = true;
      // 勾选了需要记住密码设置在localStorage 中设置记住用户名和密码
      if (loginForm.value.rememberMe) {
        localStorage.setItem("tenantId", loginForm.value.tenantId);
        localStorage.setItem('username', loginForm.value.username);
        localStorage.setItem('password', loginForm.value.password);
        localStorage.setItem('rememberMe', loginForm.value.rememberMe);
      } else {
        // 否则移除
        localStorage.removeItem("tenantId");
        localStorage.removeItem('username');
        localStorage.removeItem('password');
        localStorage.removeItem('rememberMe');
      }
      // 调用action的登录方法
      userStore.login({ ...loginForm.value, clientId: 'e5cd7e4891bf95d1d19206ce24a7b32e' }).then(() => {
        router.push({ path: redirect.value || "/" });
      }).catch((e) => {
        loading.value = false;
        // 重新获取验证码
        if (captchaEnabled.value) {
          getCode();
        }
      });
    }
  });
}
// 获取租户列表
async function initTenantList() {
  const { data } = await getTenantList();
  tenantList.value = data.voList;
  // if (tenantList.value != null && tenantList.value.length !== 0) {
  //   loginForm.value.tenantId = tenantList.value[0].tenantId;
  // }

}

//检测租户选择框的变化
watch(() => loginForm.value.tenantId, () => {
  localStorage.setItem("tenantId", loginForm.value.tenantId + '')
});

/**
 * 第三方登录
 * @param type
 */
const doSocialLogin = (type) => {
  authBinding(type).then((res) => {
    if (res.code === HttpStatus.SUCCESS) {
      // 获取授权地址跳转
      window.location.href = res.data;
    } else {
      ElMessage.error(res.msg);
    }
  });
};

onMounted(() => {
  getCode();
  initTenantList();
  getLoginData();
});

</script>

<style lang="scss" scoped>
.login-box {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #F4F5FA;
}

.login-right {
  width: 34%;
  min-width: 372px;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;

  .login-logo {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    margin-bottom: 2.1875rem;

    .login-logo-img {
      width: 4rem;
      height: 4rem;

      .el-image {
        width: 100%;
        height: 100%;
      }
    }

    .login-logo-title {
      width: 6.875rem;
      height: 2.375rem;

      .el-image {
        width: 100%;
        height: 100%;
      }
    }
  }

  .form {
    width: 21rem;
    height: 23.75rem;
    background: #FFFFFF;
    box-shadow: 0px 2px 7px 0px #EAEBF1;
    border-radius: 1rem;
    padding: 1.25rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;

    .tab {
      width: 80%;
      display: flex;
      align-items: center;
      justify-content: space-between;

      .tab-login {
        font-family: NotoSansHans, NotoSansHans;
        font-weight: 400;
        font-size: 14px;
        color: #C7C7C7;
        line-height: 21px;
        font-style: normal;
        cursor: pointer;
      }

      .is-active {
        color: #484D53;
        font-weight: 700;
      }
    }

    .login-form {
      margin-top: 2rem;

      ::v-deep(.el-button--primary) {
        background-color: #EF5A42;
        border-radius: 6px;
        border: none;
      }

      .el-input {
        height: 40px;

        input {
          height: 40px;
        }
      }

      .input-icon {
        height: 39px;
        width: 14px;
        margin-left: 0px;
      }
    }

    .code-box {
      width: 80%;
      height: 70%;
      margin-top: 2rem;

      .code-img {
        width: 100%;
        height: 100%;
        background: #FBFCFE;
        border-radius: 8px;
        // border: 1px solid #CDD4E0;

        .el-image {
          width: 100%;
          height: 100%;
        }
      }

      .code-remain {
        font-family: NotoSansHans, NotoSansHans;
        font-weight: 400;
        font-size: 13px;
        color: #484D53;
        line-height: 20px;
        text-align: center;
        font-style: normal;
        margin-top: 11px;
      }
    }
  }
}

.login-left {
  width: 66%;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;

  .el-image {
    width: 100%;
    height: 100%;
  }
}

.login-tip {
  font-size: 13px;
  text-align: center;
  color: #bfbfbf;
}

.login-code {
  width: 33%;
  height: 40px;
  float: right;

  img {
    cursor: pointer;
    vertical-align: middle;
  }
}

.el-login-footer {
  height: 40px;
  line-height: 40px;
  position: fixed;
  bottom: 0;
  width: 100%;
  text-align: center;
  color: rgb(160, 155, 155);
  font-family: Arial, serif;
  font-size: 12px;
  letter-spacing: 1px;
}

.login-code-img {
  height: 40px;
  padding-left: 12px;
}
</style>
